package com.xianggg.xservers.weixin.sdk;

import com.google.gson.Gson;
import com.thoughtworks.xstream.XStream;
import com.xianggg.xservers.weixin.sdk.type.Scope;
import com.xianggg.xservers.weixin.sdk.util.XStreamUtil;
import com.xianggg.xservers.weixin.sdk.vo.InputMsg;
import com.xianggg.xservers.weixin.sdk.vo.OAuth2Token;
import com.xianggg.xservers.weixin.sdk.vo.OutputBaseMsg;
import com.xianggg.xservers.weixin.sdk.vo.OutputTextMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class WeChatAPI {
    private static Logger logger = LoggerFactory.getLogger(WeChatAPI.class);

    /**
     * 获取用户授权
     */
    public static OAuth2Token getOauth2AccessToken(String code) throws Exception {
        String appId = WeChatConstant.getAppID();
        String secret = WeChatConstant.getSecret();
        URL url = new URL(ApiUrl.getOAuth2AccessTokenUrl(appId, secret, code));
        HttpURLConnection http = (HttpURLConnection) url.openConnection();
        http.setRequestMethod("GET");
        http.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");
        http.setDoInput(true);
        InputStream is = http.getInputStream();
        int size = is.available();
        byte[] buf = new byte[size];
        is.read(buf);
        String resp = new String(buf, "UTF-8");
        return new Gson().fromJson(resp, OAuth2Token.class);
    }

    /**
     * 授权重置
     */
    public static void redirect(String scope, String state, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 设置编码
//        response.setCharacterEncoding("utf-8");
//        response.setContentType("text/html;charset=utf-8");
        String redirectUrl = request.getRequestURL().toString();
        if(request.getQueryString()!=null){
            redirectUrl+="?"+request.getQueryString();
        }
        String authUrl = ApiUrl.getOAuth2Url(WeChatConstant.getAppID(), redirectUrl, scope, state);
        logger.info("跳转至[" + authUrl + "]获取微信权限");
        response.sendRedirect(authUrl);// 跳转到要访问的地址
    }

    /**
     * 页面默认授权方式
     */
    public static OAuth2Token auth(String state, HttpServletRequest request, HttpServletResponse response) throws Exception {
        return auth(Scope.snsapi_base, state, request, response);
    }

    /**
     * 页面跳转授权
     *
     * @param scope 需要授权类型
     * @param state 授权参数
     */
    public static OAuth2Token auth(Scope scope, String state, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String code = request.getParameter("code");
        if (code == null || code.length() == 0) {
            //        logger.info("首次进入获取code");
            WeChatAPI.redirect(scope.name(), state, request, response);
            return null;
        }
//            logger.info("获取code成功:" + code + "尝试获取token");
        OAuth2Token token = WeChatAPI.getOauth2AccessToken(code);
        if (token == null || token.getOpenid() == null || token.getOpenid().length() == 0) {
//            logger.info("微信code失效，重试");
            WeChatAPI.redirect(scope.name(), state, request, response);
            return null;
        }
        // logger.info("获取token成功，进入目标页面" + token.getOpenid());
        return token;

    }

    /**
     * 解析传入消息
     */
    public static InputMsg msgParse(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        // 处理接收消息
        ServletInputStream in = request.getInputStream();
        // 将流转换为字符串
        StringBuilder xmlMsg = new StringBuilder();
        byte[] b = new byte[4096];
        for (int n; (n = in.read(b)) != -1; ) {
            xmlMsg.append(new String(b, 0, n, "UTF-8"));
        }
        // 将POST流转换为XStream对象
        // 将xml内容转换为InputMessage对象
        return msgParse(xmlMsg.toString());
    }

    /**
     * 解析传入消息
     */
    public static InputMsg msgParse(String xml) {
        XStream xs = XStreamUtil.create();
        xs.processAnnotations(InputMsg.class);
        // 将指定节点下的xml节点数据映射为对象
        xs.alias("xml", InputMsg.class);
        return (InputMsg) xs.fromXML(xml);
    }

    /**
     * 文字回复传入消息
     */
    public static OutputTextMsg replyMsg(InputMsg inputMsg, String text) {
        OutputTextMsg outputMsg = new OutputTextMsg(inputMsg);
        outputMsg.setContent(text);
        return outputMsg;
    }

    /**
     * 回复消息转成xml
     */
    public static String replyXml(Object outputMsg, Class<? extends OutputBaseMsg> clazz) {
        XStream xs = XStreamUtil.create();
        xs.processAnnotations(clazz);
        xs.alias("xml", clazz);
        return xs.toXML(outputMsg);
    }

    /**
     * 向目标url分发且将基础token写入cookie
     */
    public static void dispatchWithCookie(String target, String state, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (WeChatConstant.getAppID() == null || WeChatConstant.getSecret() == null) {
            throw new Exception("未配置appID或secret");
        }
        OAuth2Token token = WeChatAPI.auth(state,request, response);
        if (token != null) {
            //返回信息写入cookie
            String openId = token.getOpenid();
            response.addCookie(new Cookie("openid", openId));
            response.addCookie(new Cookie("offset",state));
            request.setAttribute("state", state);
            request.getRequestDispatcher(target).forward(request, response);
        }
    }

    public static void main(String[] args) {
        String test = "<xml>\n" +
                " <ToUserName><![CDATA[toUser]]></ToUserName>\n" +
                " <FromUserName><![CDATA[fromUser]]></FromUserName>\n" +
                " <CreateTime>1348831860</CreateTime>\n" +
                " <MsgType><![CDATA[text]]></MsgType>\n" +
                " <Content><![CDATA[this is a test]]></Content>\n" +
                " <MsgId>1234567890123456</MsgId>\n" +
                " </xml>";
        InputMsg inputMsg = msgParse(test);
        OutputTextMsg outputTextMsg = replyMsg(inputMsg, "回复");
        String outXml = replyXml(outputTextMsg, OutputTextMsg.class);
        System.out.println(outXml);
    }


}
